<?php
    /**
     * TCPPC Command
     * command.php
     * Date:2024/07/31
     * @version 2.3.02
     * @author 布丁小才 zyn_games_email@yeah.net
     */

    /**
     * 错误码
     * 231：main文件夹缺少network.php（服务器文件）或api.php（API文件）或firewall.php（防火墙主类）
     * 232：服务器PID文件未找到
     * 233：服务器PID文件和进程都存在
     * 234：服务器PID文件存在，但进程不存在
     * 400：第三方程序出现错误，请留意错误信息
     */

    //是否为命令行执行
    if (!php_sapi_name() === 'cli') {  
        echo '警告：请使用终端或命令提示符（cmd）运行此脚本';
        exit;
    }

    define('TCPPC_SERVER_VERSION','2.3.02');
    $command = isset($argv[1]) ? $argv[1] : 'help';
    $command = strtolower($command);

    if (file_exists('data\tcppc.conf.json')) {
        $Config = json_decode(file_get_contents('data\tcppc.conf.json'),true);
    } else {
        $Config = array();
    }

    if (!is_array($Config)) {
        $Config = array();
    }

    if (
        (!array_key_exists('boot_mode',$Config))
        or
        (!is_int($Config["boot_mode"]))
        or
        ($Config["boot_mode"] > 1)
        or
        ($Config["boot_mode"] < 0)
    ) {
        $Config["boot_mode"] = 1;
    }

    if (!array_key_exists('port',$Config) or !is_int($Config["port"])) {
        $Config["port"] = 7161;
    }


    e('TCPPC Command');
    switch ($command) {
        case 'start':
            boot();
            break;
        case 'help':
            help();
            break;
        case 'stop':
            stop();
            break;
        case 'restart':
            stop();
            boot();
            break;
        case 'status':
            status();
            break;
        case 'reset':
            command_reset();
            break;
        default:
            help();
            break;
    }

    function e($msg) {
        //编码处理并输出
        echo iconv('utf-8','gbk//IGNORE',$msg."\n");
    }

    function boot() {
        if ((!file_exists('main\network.php')) or (!file_exists('main\api.php') or (!file_exists('main\firewall.php')))) {
            e('警告：服务器缺少必要文件，无法启动（231）');
            return;
        }

        if (!is_file('data\auth2.pwd') or (preg_replace('/\R+/','',file_get_contents('data\auth2.pwd')) == '')) {
            while (true) {
                e('请设置一个二级密码：');
                $auth2_pwd = fgets(STDIN);
                if (preg_replace('/\R+/','',$auth2_pwd) == '') {
                    e('二级密码不能为空');
                } else {
                    file_put_contents('data\auth2.pwd',md5(preg_replace('/\R+/','',$auth2_pwd)));
                    break;
                }
            }
        }

        $pid = file_get_contents('pid\network.php.pid');
        global $Config;
        if (!isProcessRunning($pid)) {
            if ($Config["boot_mode"] == 1) {
                $boot_server = proc_open('start php\php.exe main\network.php',array(),$pipes);
                if (is_resource($boot_server)) {
                    while (true) {
                        //等待服务器启动
                        if (is_file('pid\network.php.pid')) {
                            if (isProcessRunning(file_get_contents('pid\network.php.pid'))) {
                                status();
                                break;
                            }
                        }
                        sleep(0.5);
                    }
                    exit;
                } else {
                    e('服务器启动失败（400）');
                    exit;
                }
            } else if ($Config["boot_mode"] == 0) {
                exec('mshta vbscript:createobject("wscript.shell").run("php\php.exe main\network.php",0)(window.close)&&exit');
                while (true) {
                    //等待服务器启动
                    if (is_file('pid\network.php.pid')) {
                        if (isProcessRunning(file_get_contents('pid\network.php.pid'))) {
                            status();
                            break;
                        }
                    }
                    sleep(0.5);
                }
                exit;
            }
        } else {
            e('警告：服务器未关闭，无需启动（233）');
        }
    }

    function stop() {
        if (!file_exists('pid\network.php.pid')) {
            e('警告：服务器未启动，无需关闭（232）');
            return;
        }

        $pid = file_get_contents('pid\network.php.pid');
        if (isProcessRunning($pid)) {
            exec("taskkill /f /pid $pid 2>&1",$error,$code);
            if ($code == 0) {
                e('服务器已关闭');
            } else {
                e('警告：服务器关闭失败（400）');
                foreach ($error as $error_rows) {  
                    $error_row .= $error_rows.PHP_EOL;
                }
                e('错误原因'.$error_row);
            }
        } else {
            e('警告：服务器未启动，无需关闭（234）');
        }
    }

    function status() {
        global $Config;
        if (file_exists('pid\network.php.pid')) {
            if (isProcessRunning(file_get_contents('pid\network.php.pid'))) {
                e('服务器正在运行（233）');
                e('PID:'.file_get_contents('pid\network.php.pid'));
            } else {
                e('服务器未运行（234）');
            }
        } else {
            e('服务器未运行（232）');
        }

        e('服务器IP:'.gethostbyname(gethostname()));
        e('服务器名称:'.gethostname());
        e('服务器版本号:v'.TCPPC_SERVER_VERSION);
        e('服务器端口号:'.$Config["port"]);
    }

    function command_reset() {
        global $argv;
        $command2 = isset($argv[2]) ? $argv[2] : '';
        $command2 = strtolower($command2);
        switch ($command2) {
            case 'auth2.pwd':
                while (true) {
                    e('请设置一个二级密码：');
                    $auth2_pwd = fgets(STDIN);
                    if (preg_replace('/\R+/','',$auth2_pwd) == '') {
                        e('二级密码不能为空');
                    } else {
                        file_put_contents('data\auth2.pwd',md5(preg_replace('/\R+/','',$auth2_pwd)));
                        break;
                    }
                }
                e('设置成功');
                break;
            case 'connect.pwd':
                while (true) {
                    e('请设置一个服务器登录密码：');
                    e('若想清除服务器登录密码，请将data文件夹的connect.pwd文件删除');
                    $connect_pwd = fgets(STDIN);
                    if (preg_replace('/\R+/','',$connect_pwd) == '') {
                        e('服务器登录密码不能为空');
                    } else {
                        file_put_contents('data\connect.pwd',preg_replace('/\R+/','',$connect_pwd));
                        break;
                    }
                }
                e('设置成功');
                break;
            default:
                e('命令：command.bat reset [auth2.pwd|connect.pwd]');
                e('auth2.pwd：重设二级密码');
                e('connect.pwd：重设服务器登录密码');
                break;
        }
    } 

    function help() {
        e('命令：command.bat [start|stop|status|reset|help]');
        e('start：启动服务器');
        e('stop：关闭服务器');
        e('status：查看服务器状态');
        e('reset：重设服务器密码');
        e('help：查看帮助');
        return;
    }

    /** 
    * 判断进程是否存在
    * @param string|int $pid
    * @return bool
    */
    function isProcessRunning($pid) {
        //执行tasklist命令并过滤输出
        exec("tasklist /fi \"pid eq $pid\"",$output,$returnVar);
        
        //如果$returnVar不为0，则表示tasklist命令执行失败
        if ($returnVar !== 0) {
            return false;
        }
        
        //检查命令输出中是否有进程信息
        foreach ($output as $line) {
            if (preg_match("/$pid/", $line)) {
                return true;
            }
        }
        
        //没有找到匹配的PID
        return false;
    }